# This code is written by Jisung Hwang (4011hjs@kaist.ac.kr) in 2024.
# This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.

pfvtab = [
    [],
    [[13, 2, 17, 3, 15, 1, 13]],
    [[19, 4, 13, 1, 15, 5, 19]],
    [[13, 2, 17, 3, 15, 5, 19, 4, 13]],
    [[13, 6, 21, 7, 17, 2, 13]],
    [[15, 1, 13, 6, 21, 7, 17, 3, 15]],
    [[19, 4, 13, 1, 15, 5, 19], [14, 6, 21, 7, 17, 2, 14]],
    [[21, 7, 17, 3, 15, 5, 19, 4, 13, 6, 21]],
    [[21, 6, 13, 4, 19, 10, 21]],
    [[13, 2, 17, 3, 15, 1, 13], [21, 6, 14, 4, 19, 10, 21]],
    [[13, 1, 15, 5, 19, 10, 21, 6, 13]],
    [[19, 10, 21, 6, 13, 2, 17, 3, 15, 5, 19]],
    [[17, 2, 13, 4, 19, 10, 21, 7, 17]],
    [[19, 10, 21, 7, 17, 3, 15, 1, 13, 4, 19]],
    [[21, 7, 17, 2, 13, 1, 15, 5, 19, 10, 21]],
    [[21, 7, 17, 3, 15, 5, 19, 10, 21]],
    [[23, 8, 15, 3, 17, 9, 23]],
    [[15, 1, 13, 2, 17, 9, 23, 8, 15]],
    [[15, 5, 19, 4, 13, 1, 15], [23, 8, 16, 3, 17, 9, 23]],
    [[17, 9, 23, 8, 15, 5, 19, 4, 13, 2, 17]],
    [[21, 7, 17, 2, 13, 6, 21], [18, 9, 23, 8, 15, 3, 18]],
    [[23, 8, 15, 1, 13, 6, 21, 7, 17, 9, 23]],
    [[19, 4, 13, 1, 15, 5, 19], [14, 6, 21, 7, 17, 2, 14], [23, 8, 16, 3, 18, 9, 23]],
    [[21, 7, 17, 9, 23, 8, 15, 5, 19, 4, 13, 6, 21]],
    [[23, 8, 15, 3, 17, 9, 23], [21, 6, 13, 4, 19, 10, 21]],
    [[15, 1, 13, 2, 17, 9, 23, 8, 15], [21, 6, 14, 4, 19, 10, 21]],
    [[13, 1, 15, 5, 19, 10, 21, 6, 13], [23, 8, 16, 3, 17, 9, 23]],
    [[17, 9, 23, 8, 15, 5, 19, 10, 21, 6, 13, 2, 17]],
    [[17, 2, 13, 4, 19, 10, 21, 7, 17], [18, 9, 23, 8, 15, 3, 18]],
    [[23, 8, 15, 1, 13, 4, 19, 10, 21, 7, 17, 9, 23]],
    [[21, 7, 17, 2, 13, 1, 15, 5, 19, 10, 21], [23, 8, 16, 3, 18, 9, 23]],
    [[21, 7, 17, 9, 23, 8, 15, 5, 19, 10, 21]],
    [[15, 8, 23, 11, 19, 5, 15]],
    [[17, 3, 15, 1, 13, 2, 17], [16, 8, 23, 11, 19, 5, 16]],
    [[13, 1, 15, 8, 23, 11, 19, 4, 13]],
    [[23, 11, 19, 4, 13, 2, 17, 3, 15, 8, 23]],
    [[13, 6, 21, 7, 17, 2, 13], [15, 8, 23, 11, 19, 5, 15]],
    [[15, 1, 13, 6, 21, 7, 17, 3, 15], [16, 8, 23, 11, 19, 5, 16]],
    [[13, 1, 15, 8, 23, 11, 19, 4, 13], [14, 6, 21, 7, 17, 2, 14]],
    [[21, 7, 17, 3, 15, 8, 23, 11, 19, 4, 13, 6, 21]],
    [[19, 10, 21, 6, 13, 4, 19], [23, 11, 20, 5, 15, 8, 23]],
    [[13, 2, 17, 3, 15, 1, 13], [21, 6, 14, 4, 19, 10, 21], [16, 8, 23, 11, 20, 5, 16]],
    [[15, 8, 23, 11, 19, 10, 21, 6, 13, 1, 15]],
    [[19, 10, 21, 6, 13, 2, 17, 3, 15, 8, 23, 11, 19]],
    [[13, 4, 19, 10, 21, 7, 17, 2, 13], [23, 11, 20, 5, 15, 8, 23]],
    [[19, 10, 21, 7, 17, 3, 15, 1, 13, 4, 19], [16, 8, 23, 11, 20, 5, 16]],
    [[21, 7, 17, 2, 13, 1, 15, 8, 23, 11, 19, 10, 21]],
    [[19, 10, 21, 7, 17, 3, 15, 8, 23, 11, 19]],
    [[15, 3, 17, 9, 23, 11, 19, 5, 15]],
    [[23, 11, 19, 5, 15, 1, 13, 2, 17, 9, 23]],
    [[17, 9, 23, 11, 19, 4, 13, 1, 15, 3, 17]],
    [[17, 9, 23, 11, 19, 4, 13, 2, 17]],
    [[15, 3, 18, 9, 23, 11, 19, 5, 15], [21, 7, 17, 2, 13, 6, 21]],
    [[13, 6, 21, 7, 17, 9, 23, 11, 19, 5, 15, 1, 13]],
    [[18, 9, 23, 11, 19, 4, 13, 1, 15, 3, 18], [14, 6, 21, 7, 17, 2, 14]],
    [[17, 9, 23, 11, 19, 4, 13, 6, 21, 7, 17]],
    [[20, 5, 15, 3, 17, 9, 23, 11, 20], [19, 10, 21, 6, 13, 4, 19]],
    [[23, 11, 20, 5, 15, 1, 13, 2, 17, 9, 23], [21, 6, 14, 4, 19, 10, 21]],
    [[17, 9, 23, 11, 19, 10, 21, 6, 13, 1, 15, 3, 17]],
    [[23, 11, 19, 10, 21, 6, 13, 2, 17, 9, 23]],
    [[17, 2, 13, 4, 19, 10, 21, 7, 17], [15, 3, 18, 9, 23, 11, 20, 5, 15]],
    [[19, 10, 21, 7, 17, 9, 23, 11, 20, 5, 15, 1, 13, 4, 19]],
    [[21, 7, 17, 2, 13, 1, 15, 3, 18, 9, 23, 11, 19, 10, 21]],
    [[17, 9, 23, 11, 19, 10, 21, 7, 17]],
    [[23, 9, 17, 7, 21, 12, 23]],
    [[17, 3, 15, 1, 13, 2, 17], [23, 9, 18, 7, 21, 12, 23]],
    [[19, 4, 13, 1, 15, 5, 19], [23, 9, 17, 7, 21, 12, 23]],
    [[13, 2, 17, 3, 15, 5, 19, 4, 13], [23, 9, 18, 7, 21, 12, 23]],
    [[17, 2, 13, 6, 21, 12, 23, 9, 17]],
    [[21, 12, 23, 9, 17, 3, 15, 1, 13, 6, 21]],
    [[17, 2, 14, 6, 21, 12, 23, 9, 17], [19, 4, 13, 1, 15, 5, 19]],
    [[15, 5, 19, 4, 13, 6, 21, 12, 23, 9, 17, 3, 15]],
    [[19, 10, 21, 6, 13, 4, 19], [22, 12, 23, 9, 17, 7, 22]],
    [[15, 1, 13, 2, 17, 3, 15], [14, 4, 19, 10, 21, 6, 14], [23, 9, 18, 7, 22, 12, 23]],
    [[21, 6, 13, 1, 15, 5, 19, 10, 21], [22, 12, 23, 9, 17, 7, 22]],
    [[19, 10, 21, 6, 13, 2, 17, 3, 15, 5, 19], [23, 9, 18, 7, 22, 12, 23]],
    [[23, 9, 17, 2, 13, 4, 19, 10, 21, 12, 23]],
    [[19, 10, 21, 12, 23, 9, 17, 3, 15, 1, 13, 4, 19]],
    [[15, 5, 19, 10, 21, 12, 23, 9, 17, 2, 13, 1, 15]],
    [[19, 10, 21, 12, 23, 9, 17, 3, 15, 5, 19]],
    [[15, 3, 17, 7, 21, 12, 23, 8, 15]],
    [[21, 12, 23, 8, 15, 1, 13, 2, 17, 7, 21]],
    [[16, 3, 17, 7, 21, 12, 23, 8, 16], [15, 5, 19, 4, 13, 1, 15]],
    [[19, 4, 13, 2, 17, 7, 21, 12, 23, 8, 15, 5, 19]],
    [[23, 8, 15, 3, 17, 2, 13, 6, 21, 12, 23]],
    [[23, 8, 15, 1, 13, 6, 21, 12, 23]],
    [[23, 8, 16, 3, 17, 2, 14, 6, 21, 12, 23], [19, 4, 13, 1, 15, 5, 19]],
    [[23, 8, 15, 5, 19, 4, 13, 6, 21, 12, 23]],
    [[17, 7, 22, 12, 23, 8, 15, 3, 17], [19, 10, 21, 6, 13, 4, 19]],
    [[22, 12, 23, 8, 15, 1, 13, 2, 17, 7, 22], [14, 4, 19, 10, 21, 6, 14]],
    [[13, 1, 15, 5, 19, 10, 21, 6, 13], [16, 3, 17, 7, 22, 12, 23, 8, 16]],
    [[19, 10, 21, 6, 13, 2, 17, 7, 22, 12, 23, 8, 15, 5, 19]],
    [[23, 8, 15, 3, 17, 2, 13, 4, 19, 10, 21, 12, 23]],
    [[21, 12, 23, 8, 15, 1, 13, 4, 19, 10, 21]],
    [[15, 5, 19, 10, 21, 12, 23, 8, 16, 3, 17, 2, 13, 1, 15]],
    [[23, 8, 15, 5, 19, 10, 21, 12, 23]],
    [[23, 11, 19, 5, 15, 8, 23], [21, 12, 24, 9, 17, 7, 21]],
    [[15, 1, 13, 2, 17, 3, 15], [19, 5, 16, 8, 23, 11, 19], [18, 7, 21, 12, 24, 9, 18]],
    [[15, 8, 23, 11, 19, 4, 13, 1, 15], [21, 12, 24, 9, 17, 7, 21]],
    [[23, 11, 19, 4, 13, 2, 17, 3, 15, 8, 23], [18, 7, 21, 12, 24, 9, 18]],
    [[24, 9, 17, 2, 13, 6, 21, 12, 24], [23, 11, 19, 5, 15, 8, 23]],
    [[21, 12, 24, 9, 17, 3, 15, 1, 13, 6, 21], [19, 5, 16, 8, 23, 11, 19]],
    [[13, 1, 15, 8, 23, 11, 19, 4, 13], [17, 2, 14, 6, 21, 12, 24, 9, 17]],
    [[23, 11, 19, 4, 13, 6, 21, 12, 24, 9, 17, 3, 15, 8, 23]],
    [[13, 4, 19, 10, 21, 6, 13], [20, 5, 15, 8, 23, 11, 20], [17, 7, 22, 12, 24, 9, 17]],
    [[13, 2, 17, 3, 15, 1, 13], [21, 6, 14, 4, 19, 10, 21], [16, 8, 23, 11, 20, 5, 16], [24, 9, 18, 7, 22, 12, 24]],
    [[15, 8, 23, 11, 19, 10, 21, 6, 13, 1, 15], [17, 7, 22, 12, 24, 9, 17]],
    [[19, 10, 21, 6, 13, 2, 17, 3, 15, 8, 23, 11, 19], [24, 9, 18, 7, 22, 12, 24]],
    [[24, 9, 17, 2, 13, 4, 19, 10, 21, 12, 24], [20, 5, 15, 8, 23, 11, 20]],
    [[19, 10, 21, 12, 24, 9, 17, 3, 15, 1, 13, 4, 19], [16, 8, 23, 11, 20, 5, 16]],
    [[15, 8, 23, 11, 19, 10, 21, 12, 24, 9, 17, 2, 13, 1, 15]],
    [[19, 10, 21, 12, 24, 9, 17, 3, 15, 8, 23, 11, 19]],
    [[17, 7, 21, 12, 23, 11, 19, 5, 15, 3, 17]],
    [[23, 11, 19, 5, 15, 1, 13, 2, 17, 7, 21, 12, 23]],
    [[19, 4, 13, 1, 15, 3, 17, 7, 21, 12, 23, 11, 19]],
    [[23, 11, 19, 4, 13, 2, 17, 7, 21, 12, 23]],
    [[13, 6, 21, 12, 23, 11, 19, 5, 15, 3, 17, 2, 13]],
    [[21, 12, 23, 11, 19, 5, 15, 1, 13, 6, 21]],
    [[19, 4, 13, 1, 15, 3, 17, 2, 14, 6, 21, 12, 23, 11, 19]],
    [[13, 6, 21, 12, 23, 11, 19, 4, 13]],
    [[17, 7, 22, 12, 23, 11, 20, 5, 15, 3, 17], [13, 4, 19, 10, 21, 6, 13]],
    [[23, 11, 20, 5, 15, 1, 13, 2, 17, 7, 22, 12, 23], [21, 6, 14, 4, 19, 10, 21]],
    [[21, 6, 13, 1, 15, 3, 17, 7, 22, 12, 23, 11, 19, 10, 21]],
    [[23, 11, 19, 10, 21, 6, 13, 2, 17, 7, 22, 12, 23]],
    [[13, 4, 19, 10, 21, 12, 23, 11, 20, 5, 15, 3, 17, 2, 13]],
    [[21, 12, 23, 11, 20, 5, 15, 1, 13, 4, 19, 10, 21]],
    [[17, 2, 13, 1, 15, 3, 17], [23, 11, 19, 10, 21, 12, 23]],
    [[23, 11, 19, 10, 21, 12, 23]],
    [[19, 11, 23, 12, 21, 10, 19]],
    [[13, 2, 17, 3, 15, 1, 13], [19, 11, 23, 12, 21, 10, 19]],
    [[15, 5, 19, 4, 13, 1, 15], [20, 11, 23, 12, 21, 10, 20]],
    [[19, 4, 13, 2, 17, 3, 15, 5, 19], [20, 11, 23, 12, 21, 10, 20]],
    [[21, 7, 17, 2, 13, 6, 21], [23, 12, 22, 10, 19, 11, 23]],
    [[13, 6, 21, 7, 17, 3, 15, 1, 13], [23, 12, 22, 10, 19, 11, 23]],
    [[13, 1, 15, 5, 19, 4, 13], [17, 2, 14, 6, 21, 7, 17], [20, 11, 23, 12, 22, 10, 20]],
    [[21, 7, 17, 3, 15, 5, 19, 4, 13, 6, 21], [20, 11, 23, 12, 22, 10, 20]],
    [[13, 4, 19, 11, 23, 12, 21, 6, 13]],
    [[14, 4, 19, 11, 23, 12, 21, 6, 14], [13, 2, 17, 3, 15, 1, 13]],
    [[23, 12, 21, 6, 13, 1, 15, 5, 19, 11, 23]],
    [[17, 3, 15, 5, 19, 11, 23, 12, 21, 6, 13, 2, 17]],
    [[19, 11, 23, 12, 21, 7, 17, 2, 13, 4, 19]],
    [[17, 3, 15, 1, 13, 4, 19, 11, 23, 12, 21, 7, 17]],
    [[21, 7, 17, 2, 13, 1, 15, 5, 19, 11, 23, 12, 21]],
    [[21, 7, 17, 3, 15, 5, 19, 11, 23, 12, 21]],
    [[17, 9, 23, 8, 15, 3, 17], [24, 12, 21, 10, 19, 11, 24]],
    [[23, 8, 15, 1, 13, 2, 17, 9, 23], [24, 12, 21, 10, 19, 11, 24]],
    [[13, 1, 15, 5, 19, 4, 13], [16, 3, 17, 9, 23, 8, 16], [21, 10, 20, 11, 24, 12, 21]],
    [[17, 9, 23, 8, 15, 5, 19, 4, 13, 2, 17], [21, 10, 20, 11, 24, 12, 21]],
    [[17, 2, 13, 6, 21, 7, 17], [15, 3, 18, 9, 23, 8, 15], [22, 10, 19, 11, 24, 12, 22]],
    [[23, 8, 15, 1, 13, 6, 21, 7, 17, 9, 23], [22, 10, 19, 11, 24, 12, 22]],
    [[19, 4, 13, 1, 15, 5, 19], [14, 6, 21, 7, 17, 2, 14], [23, 8, 16, 3, 18, 9, 23], [20, 11, 24, 12, 22, 10, 20]],
    [[21, 7, 17, 9, 23, 8, 15, 5, 19, 4, 13, 6, 21], [20, 11, 24, 12, 22, 10, 20]],
    [[19, 11, 24, 12, 21, 6, 13, 4, 19], [17, 9, 23, 8, 15, 3, 17]],
    [[15, 1, 13, 2, 17, 9, 23, 8, 15], [14, 4, 19, 11, 24, 12, 21, 6, 14]],
    [[24, 12, 21, 6, 13, 1, 15, 5, 19, 11, 24], [16, 3, 17, 9, 23, 8, 16]],
    [[17, 9, 23, 8, 15, 5, 19, 11, 24, 12, 21, 6, 13, 2, 17]],
    [[19, 11, 24, 12, 21, 7, 17, 2, 13, 4, 19], [15, 3, 18, 9, 23, 8, 15]],
    [[23, 8, 15, 1, 13, 4, 19, 11, 24, 12, 21, 7, 17, 9, 23]],
    [[21, 7, 17, 2, 13, 1, 15, 5, 19, 11, 24, 12, 21], [23, 8, 16, 3, 18, 9, 23]],
    [[21, 7, 17, 9, 23, 8, 15, 5, 19, 11, 24, 12, 21]],
    [[19, 5, 15, 8, 23, 12, 21, 10, 19]],
    [[19, 5, 16, 8, 23, 12, 21, 10, 19], [17, 3, 15, 1, 13, 2, 17]],
    [[23, 12, 21, 10, 19, 4, 13, 1, 15, 8, 23]],
    [[13, 2, 17, 3, 15, 8, 23, 12, 21, 10, 19, 4, 13]],
    [[22, 10, 19, 5, 15, 8, 23, 12, 22], [21, 7, 17, 2, 13, 6, 21]],
    [[15, 1, 13, 6, 21, 7, 17, 3, 15], [19, 5, 16, 8, 23, 12, 22, 10, 19]],
    [[23, 12, 22, 10, 19, 4, 13, 1, 15, 8, 23], [17, 2, 14, 6, 21, 7, 17]],
    [[21, 7, 17, 3, 15, 8, 23, 12, 22, 10, 19, 4, 13, 6, 21]],
    [[15, 8, 23, 12, 21, 6, 13, 4, 19, 5, 15]],
    [[16, 8, 23, 12, 21, 6, 14, 4, 19, 5, 16], [13, 2, 17, 3, 15, 1, 13]],
    [[15, 8, 23, 12, 21, 6, 13, 1, 15]],
    [[15, 8, 23, 12, 21, 6, 13, 2, 17, 3, 15]],
    [[17, 2, 13, 4, 19, 5, 15, 8, 23, 12, 21, 7, 17]],
    [[17, 3, 15, 1, 13, 4, 19, 5, 16, 8, 23, 12, 21, 7, 17]],
    [[23, 12, 21, 7, 17, 2, 13, 1, 15, 8, 23]],
    [[15, 8, 23, 12, 21, 7, 17, 3, 15]],
    [[21, 10, 19, 5, 15, 3, 17, 9, 23, 12, 21]],
    [[13, 2, 17, 9, 23, 12, 21, 10, 19, 5, 15, 1, 13]],
    [[17, 9, 23, 12, 21, 10, 19, 4, 13, 1, 15, 3, 17]],
    [[17, 9, 23, 12, 21, 10, 19, 4, 13, 2, 17]],
    [[22, 10, 19, 5, 15, 3, 18, 9, 23, 12, 22], [17, 2, 13, 6, 21, 7, 17]],
    [[13, 6, 21, 7, 17, 9, 23, 12, 22, 10, 19, 5, 15, 1, 13]],
    [[18, 9, 23, 12, 22, 10, 19, 4, 13, 1, 15, 3, 18], [14, 6, 21, 7, 17, 2, 14]],
    [[17, 9, 23, 12, 22, 10, 19, 4, 13, 6, 21, 7, 17]],
    [[15, 3, 17, 9, 23, 12, 21, 6, 13, 4, 19, 5, 15]],
    [[13, 2, 17, 9, 23, 12, 21, 6, 14, 4, 19, 5, 15, 1, 13]],
    [[23, 12, 21, 6, 13, 1, 15, 3, 17, 9, 23]],
    [[21, 6, 13, 2, 17, 9, 23, 12, 21]],
    [[17, 2, 13, 4, 19, 5, 15, 3, 18, 9, 23, 12, 21, 7, 17]],
    [[17, 9, 23, 12, 21, 7, 17], [13, 4, 19, 5, 15, 1, 13]],
    [[23, 12, 21, 7, 17, 2, 13, 1, 15, 3, 18, 9, 23]],
    [[17, 9, 23, 12, 21, 7, 17]],
    [[17, 7, 21, 10, 19, 11, 23, 9, 17]],
    [[18, 7, 21, 10, 19, 11, 23, 9, 18], [17, 3, 15, 1, 13, 2, 17]],
    [[21, 10, 20, 11, 23, 9, 17, 7, 21], [15, 5, 19, 4, 13, 1, 15]],
    [[13, 2, 17, 3, 15, 5, 19, 4, 13], [18, 7, 21, 10, 20, 11, 23, 9, 18]],
    [[19, 11, 23, 9, 17, 2, 13, 6, 21, 10, 19]],
    [[15, 1, 13, 6, 21, 10, 19, 11, 23, 9, 17, 3, 15]],
    [[20, 11, 23, 9, 17, 2, 14, 6, 21, 10, 20], [13, 1, 15, 5, 19, 4, 13]],
    [[15, 5, 19, 4, 13, 6, 21, 10, 20, 11, 23, 9, 17, 3, 15]],
    [[23, 9, 17, 7, 21, 6, 13, 4, 19, 11, 23]],
    [[23, 9, 18, 7, 21, 6, 14, 4, 19, 11, 23], [15, 1, 13, 2, 17, 3, 15]],
    [[13, 1, 15, 5, 19, 11, 23, 9, 17, 7, 21, 6, 13]],
    [[17, 3, 15, 5, 19, 11, 23, 9, 18, 7, 21, 6, 13, 2, 17]],
    [[23, 9, 17, 2, 13, 4, 19, 11, 23]],
    [[23, 9, 17, 3, 15, 1, 13, 4, 19, 11, 23]],
    [[19, 11, 23, 9, 17, 2, 13, 1, 15, 5, 19]],
    [[23, 9, 17, 3, 15, 5, 19, 11, 23]],
    [[21, 10, 19, 11, 23, 8, 15, 3, 17, 7, 21]],
    [[15, 1, 13, 2, 17, 7, 21, 10, 19, 11, 23, 8, 15]],
    [[21, 10, 20, 11, 23, 8, 16, 3, 17, 7, 21], [13, 1, 15, 5, 19, 4, 13]],
    [[19, 4, 13, 2, 17, 7, 21, 10, 20, 11, 23, 8, 15, 5, 19]],
    [[23, 8, 15, 3, 17, 2, 13, 6, 21, 10, 19, 11, 23]],
    [[23, 8, 15, 1, 13, 6, 21, 10, 19, 11, 23]],
    [[23, 8, 16, 3, 17, 2, 14, 6, 21, 10, 20, 11, 23], [19, 4, 13, 1, 15, 5, 19]],
    [[23, 8, 15, 5, 19, 4, 13, 6, 21, 10, 20, 11, 23]],
    [[15, 3, 17, 7, 21, 6, 13, 4, 19, 11, 23, 8, 15]],
    [[15, 1, 13, 2, 17, 7, 21, 6, 14, 4, 19, 11, 23, 8, 15]],
    [[13, 1, 15, 5, 19, 11, 23, 8, 16, 3, 17, 7, 21, 6, 13]],
    [[23, 8, 15, 5, 19, 11, 23], [21, 6, 13, 2, 17, 7, 21]],
    [[19, 11, 23, 8, 15, 3, 17, 2, 13, 4, 19]],
    [[13, 4, 19, 11, 23, 8, 15, 1, 13]],
    [[19, 11, 23, 8, 16, 3, 17, 2, 13, 1, 15, 5, 19]],
    [[23, 8, 15, 5, 19, 11, 23]],
    [[17, 7, 21, 10, 19, 5, 15, 8, 23, 9, 17]],
    [[18, 7, 21, 10, 19, 5, 16, 8, 23, 9, 18], [15, 1, 13, 2, 17, 3, 15]],
    [[13, 1, 15, 8, 23, 9, 17, 7, 21, 10, 19, 4, 13]],
    [[13, 2, 17, 3, 15, 8, 23, 9, 18, 7, 21, 10, 19, 4, 13]],
    [[17, 2, 13, 6, 21, 10, 19, 5, 15, 8, 23, 9, 17]],
    [[15, 1, 13, 6, 21, 10, 19, 5, 16, 8, 23, 9, 17, 3, 15]],
    [[13, 1, 15, 8, 23, 9, 17, 2, 14, 6, 21, 10, 19, 4, 13]],
    [[13, 6, 21, 10, 19, 4, 13], [15, 8, 23, 9, 17, 3, 15]],
    [[15, 8, 23, 9, 17, 7, 21, 6, 13, 4, 19, 5, 15]],
    [[16, 8, 23, 9, 18, 7, 21, 6, 14, 4, 19, 5, 16], [13, 2, 17, 3, 15, 1, 13]],
    [[15, 8, 23, 9, 17, 7, 21, 6, 13, 1, 15]],
    [[15, 8, 23, 9, 18, 7, 21, 6, 13, 2, 17, 3, 15]],
    [[23, 9, 17, 2, 13, 4, 19, 5, 15, 8, 23]],
    [[23, 9, 17, 3, 15, 1, 13, 4, 19, 5, 16, 8, 23]],
    [[17, 2, 13, 1, 15, 8, 23, 9, 17]],
    [[15, 8, 23, 9, 17, 3, 15]],
    [[17, 7, 21, 10, 19, 5, 15, 3, 17]],
    [[17, 7, 21, 10, 19, 5, 15, 1, 13, 2, 17]],
    [[21, 10, 19, 4, 13, 1, 15, 3, 17, 7, 21]],
    [[17, 7, 21, 10, 19, 4, 13, 2, 17]],
    [[21, 10, 19, 5, 15, 3, 17, 2, 13, 6, 21]],
    [[19, 5, 15, 1, 13, 6, 21, 10, 19]],
    [[21, 10, 19, 4, 13, 1, 15, 3, 17, 2, 14, 6, 21]],
    [[13, 6, 21, 10, 19, 4, 13]],
    [[17, 7, 21, 6, 13, 4, 19, 5, 15, 3, 17]],
    [[17, 7, 21, 6, 14, 4, 19, 5, 15, 1, 13, 2, 17]],
    [[15, 3, 17, 7, 21, 6, 13, 1, 15]],
    [[21, 6, 13, 2, 17, 7, 21]],
    [[15, 3, 17, 2, 13, 4, 19, 5, 15]],
    [[13, 4, 19, 5, 15, 1, 13]],
    [[17, 2, 13, 1, 15, 3, 17]],
    []
];

vitogi = [
    [0, 0, 0, -1],
    
    [0, 0, 0, 0], [0, 0, 0, 1], [0, 0, 0, 2], [0, 0, 1, 1], [0, 0, 1, 2], [0, 1, 0, 0],
    [0, 1, 0, 2], [1, 0, 0, 0], [1, 0, 0, 1], [0, 1, 1, 2], [1, 0, 1, 1], [1, 1, 0, 0],
    
    [0, 0, 0, 3], [0, 0, 0, 4], [0, 0, 0, 5], [0, 0, 0, 6], [0, 0, 0, 7], [0, 0, 0, 8],
    [0, 0, 1, 7], [0, 0, 1, 8], [0, 1, 0, 5], [0, 1, 0, 6], [1, 0, 0, 3], [1, 0, 0, 4],

    [0, 0, 0, 9], [0, 0, 0, 10], [0, 0, 0, 11], [0, 0, 0, 12]
];

lctab_2d = [
    [],
    [[0, 0, 1], [0, 0, 0]],
    [[0, 0, 1], [0, 1, 0]],
    [[0, 0, 0], [0, 1, 0]],
    [[0, 0, 0], [1, 0, 1]],
    [[0, 0, 1], [1, 0, 1]],
    [[0, 0, 1], [0, 1, 0], [0, 0, 0], [1, 0, 1]],
    [[0, 1, 0], [1, 0, 1]],
    [[0, 1, 0], [1, 0, 1]],
    [[0, 0, 1], [0, 0, 0], [0, 1, 0], [1, 0, 1]],
    [[0, 0, 1], [1, 0, 1]],
    [[0, 0, 0], [1, 0, 1]],
    [[0, 0, 0], [0, 1, 0]],
    [[0, 0, 1], [0, 1, 0]],
    [[0, 0, 1], [0, 0, 0]],
    []
];

cstrtab = [
    [6, [[0, 5, 3]], [[0, 3, 6]]],
    [9, [[1, 2, 4]], [[1, 7, 2]]],
    [18, [[0, 5, 3]], [[0, 6, 5]]],
    [20, [[0, 3, 6]], [[0, 6, 5]]],
    [22, [[0, 5, 3]], [[0, 3, 6]], [[0, 6, 5]]],
    [24, [[0, 6, 5]], [[1, 7, 2]]],
    [25, [[4, 1, 2], [5, 0, 6]], [[1, 7, 2]]],
    [26, [[3, 0, 5], [2, 1, 7]], [[0, 6, 5]]],
    [28, [[3, 6, 0], [1, 7, 2]], [[0, 6, 5]]],
    [30, [[0, 5, 3]], [[0, 6, 5]]],
    [33, [[1, 2, 4]], [[1, 4, 7]]],
    [36, [[0, 3, 6]], [[1, 4, 7]]],
    [37, [[2, 4, 1], [3, 6, 0]], [[1, 4, 7]]],
    [38, [[5, 3, 0], [4, 7, 1]], [[0, 3, 6]]],
    [40, [[1, 7, 2]], [[1, 4, 7]]],
    [41, [[1, 2, 4]], [[1, 7, 2]], [[1, 4, 7]]],
    [44, [[2, 1, 7], [0, 3, 6]], [[1, 4, 7]]],
    [45, [[1, 2, 4]], [[1, 4, 7]]],
    [52, [[5, 0, 6], [1, 4, 7]], [[0, 3, 6]]],
    [54, [[0, 5, 3]], [[0, 3, 6]]],
    [56, [[4, 7, 1], [0, 6, 5]], [[1, 7, 2]]],
    [57, [[1, 2, 4]], [[1, 7, 2]]],
    [60, [[3, 6, 0], [1, 7, 2]], [[0, 6, 5], [1, 4, 7]]],
    [61, [[1, 2, 7], [4, 1, 7]]],
    [62, [[0, 6, 3], [5, 6, 0]]],
    [65, [[2, 4, 1]], [[2, 7, 4]]],
    [66, [[0, 5, 3]], [[2, 7, 4]]],
    [67, [[1, 2, 4], [3, 0, 5]], [[2, 7, 4]]],
    [70, [[6, 0, 3], [4, 2, 7]], [[0, 5, 3]]],
    [72, [[2, 1, 7]], [[2, 7, 4]]],
    [73, [[2, 4, 1]], [[2, 1, 7]], [[2, 7, 4]]],
    [74, [[1, 7, 2], [0, 5, 3]], [[2, 7, 4]]],
    [75, [[2, 4, 1]], [[2, 7, 4]]],
    [82, [[6, 5, 0], [2, 7, 4]], [[0, 5, 3]]],
    [86, [[0, 3, 6]], [[0, 5, 3]]],
    [88, [[4, 2, 7], [0, 6, 5]], [[2, 1, 7]]],
    [89, [[2, 4, 1]], [[2, 1, 7]]],
    [90, [[3, 0, 5], [2, 1, 7]], [[0, 6, 5], [2, 7, 4]]],
    [91, [[2, 7, 1], [4, 7, 2]]],
    [94, [[0, 3, 5], [6, 0, 5]]],
    [96, [[4, 7, 1]], [[4, 2, 7]]],
    [97, [[4, 1, 2]], [[4, 7, 1]], [[4, 2, 7]]],
    [98, [[1, 4, 7], [0, 5, 3]], [[4, 2, 7]]],
    [99, [[4, 1, 2]], [[4, 2, 7]]],
    [100, [[2, 7, 4], [0, 3, 6]], [[4, 7, 1]]],
    [101, [[4, 1, 2]], [[4, 7, 1]]],
    [102, [[5, 3, 0], [4, 7, 1]], [[0, 3, 6], [4, 2, 7]]],
    [103, [[4, 1, 7], [2, 4, 7]]],
    [104, [[7, 2, 1]], [[7, 1, 4]], [[7, 4, 2]]],
    [105, [[1, 2, 4]], [[1, 7, 2]], [[1, 4, 7]], [[2, 7, 4]]],
    [106, [[7, 2, 1]], [[7, 4, 2]]],
    [107, [[2, 4, 1]], [[2, 7, 4]]],
    [108, [[7, 2, 1]], [[7, 1, 4]]],
    [109, [[1, 2, 4]], [[1, 4, 7]]],
    [110, [[7, 4, 1], [2, 4, 7]]],
    [111, [[1, 7, 4], [2, 4, 7]]],
    [118, [[0, 3, 5], [6, 3, 0]]],
    [120, [[7, 1, 4]], [[7, 2, 1]]],
    [121, [[1, 2, 4]], [[1, 7, 2]]],
    [122, [[7, 1, 2], [4, 7, 2]]],
    [123, [[1, 2, 7], [4, 7, 2]]],
    [124, [[7, 1, 2], [4, 1, 7]]],
    [125, [[2, 7, 1], [4, 1, 7]]],
    [126, [[1, 2, 4]], [[3, 5, 6]]],
    [129, [[1, 2, 4]], [[3, 5, 6]]],
    [130, [[3, 0, 5]], [[3, 5, 6]]],
    [131, [[0, 5, 3], [2, 4, 1]], [[3, 5, 6]]],
    [132, [[3, 6, 0]], [[3, 5, 6]]],
    [133, [[0, 3, 6], [1, 2, 4]], [[3, 5, 6]]],
    [134, [[3, 0, 5]], [[3, 6, 0]], [[3, 5, 6]]],
    [135, [[3, 0, 5]], [[3, 5, 6]]],
    [137, [[7, 2, 1], [5, 6, 3]], [[1, 2, 4]]],
    [144, [[5, 0, 6]], [[5, 6, 3]]],
    [145, [[0, 6, 5], [1, 2, 4]], [[5, 6, 3]]],
    [146, [[5, 3, 0]], [[5, 0, 6]], [[5, 6, 3]]],
    [147, [[5, 3, 0]], [[5, 6, 3]]],
    [148, [[6, 0, 3]], [[6, 5, 0]], [[6, 3, 5]]],
    [149, [[6, 0, 3]], [[6, 3, 5]]],
    [150, [[0, 5, 3]], [[0, 3, 6]], [[0, 6, 5]], [[3, 5, 6]]],
    [151, [[3, 0, 5]], [[3, 5, 6]]],
    [152, [[3, 5, 6], [1, 7, 2]], [[5, 0, 6]]],
    [153, [[4, 1, 2], [5, 0, 6]], [[1, 7, 2], [5, 6, 3]]],
    [154, [[5, 3, 0]], [[5, 0, 6]]],
    [155, [[5, 6, 0], [3, 6, 5]]],
    [156, [[6, 0, 3]], [[6, 5, 0]]],
    [157, [[6, 0, 5], [3, 6, 5]]],
    [158, [[0, 5, 3]], [[0, 6, 5]]],
    [159, [[0, 5, 6], [3, 6, 5]]],
    [161, [[7, 1, 4], [3, 5, 6]], [[1, 2, 4]]],
    [164, [[5, 6, 3], [1, 4, 7]], [[3, 6, 0]]],
    [165, [[2, 4, 1], [3, 6, 0]], [[1, 4, 7], [3, 5, 6]]],
    [166, [[3, 0, 5]], [[3, 6, 0]]],
    [167, [[3, 0, 6], [5, 3, 6]]],
    [169, [[1, 7, 2]], [[1, 2, 4]]],
    [173, [[1, 4, 2], [7, 4, 1]]],
    [180, [[6, 5, 0]], [[6, 0, 3]]],
    [181, [[6, 3, 0], [5, 3, 6]]],
    [182, [[0, 5, 3]], [[0, 3, 6]]],
    [183, [[0, 6, 3], [5, 3, 6]]],
    [185, [[1, 4, 2], [7, 1, 2]]],
    [188, [[6, 3, 0], [5, 6, 0]]],
    [189, [[2, 7, 4]], [[0, 5, 3]]],
    [190, [[3, 0, 6], [5, 6, 0]]],
    [193, [[7, 4, 2], [3, 5, 6]], [[2, 4, 1]]],
    [194, [[6, 3, 5], [2, 7, 4]], [[3, 0, 5]]],
    [195, [[1, 2, 4], [3, 0, 5]], [[2, 7, 4], [3, 5, 6]]],
    [198, [[3, 6, 0]], [[3, 0, 5]]],
    [199, [[3, 5, 0], [6, 5, 3]]],
    [201, [[2, 1, 7]], [[2, 4, 1]]],
    [203, [[2, 1, 4], [7, 2, 4]]],
    [210, [[5, 0, 6]], [[5, 3, 0]]],
    [211, [[5, 0, 3], [6, 5, 3]]],
    [214, [[0, 3, 6]], [[0, 5, 3]]],
    [215, [[0, 3, 5], [6, 5, 3]]],
    [217, [[2, 1, 4], [7, 1, 2]]],
    [218, [[5, 0, 3], [6, 0, 5]]],
    [219, [[1, 4, 7]], [[0, 3, 6]]],
    [222, [[3, 5, 0], [6, 0, 5]]],
    [225, [[4, 7, 1]], [[4, 1, 2]]],
    [227, [[4, 2, 1], [7, 2, 4]]],
    [229, [[4, 2, 1], [7, 4, 1]]],
    [230, [[3, 5, 0], [6, 3, 0]]],
    [231, [[1, 7, 2]], [[0, 6, 5]]],
    [233, [[1, 7, 2]], [[1, 2, 4]]],
    [235, [[1, 4, 2], [7, 2, 4]]],
    [237, [[2, 1, 4], [7, 4, 1]]],
    [246, [[5, 0, 3], [6, 3, 0]]],
    [249, [[4, 2, 1], [7, 1, 2]]]
];

cpnttab = [
    [6, [4, 4, 20], [4, 20, 4]],
    [9, [4, 4, 4], [4, 20, 20]],
    [18, [4, 4, 20], [20, 4, 4]],
    [20, [4, 20, 4], [20, 4, 4]],
    [22, [4, 4, 20], [4, 20, 4], [20, 4, 4]],
    [24, [20, 4, 4], [4, 20, 20]],
    [25, [12, 3, 3], [4, 20, 20]],
    [26, [3, 12, 21], [20, 4, 4]],
    [28, [3, 21, 12], [20, 4, 4]],
    [30, [4, 4, 20], [20, 4, 4]],
    [33, [4, 4, 4], [20, 4, 20]],
    [36, [4, 20, 4], [20, 4, 20]],
    [37, [3, 12, 3], [20, 4, 20]],
    [38, [12, 3, 21], [4, 20, 4]],
    [40, [4, 20, 20], [20, 4, 20]],
    [41, [4, 4, 4], [4, 20, 20], [20, 4, 20]],
    [44, [3, 21, 12], [20, 4, 20]],
    [45, [4, 4, 4], [20, 4, 20]],
    [52, [21, 3, 12], [4, 20, 4]],
    [54, [4, 4, 20], [4, 20, 4]],
    [56, [21, 3, 12], [4, 20, 20]],
    [57, [4, 4, 4], [4, 20, 20]],
    [60, [3, 21, 12], [21, 3, 12]],
    [65, [4, 4, 4], [20, 20, 4]],
    [66, [4, 4, 20], [20, 20, 4]],
    [67, [3, 3, 12], [20, 20, 4]],
    [70, [12, 21, 3], [4, 4, 20]],
    [72, [4, 20, 20], [20, 20, 4]],
    [73, [4, 4, 4], [4, 20, 20], [20, 20, 4]],
    [74, [3, 12, 21], [20, 20, 4]],
    [75, [4, 4, 4], [20, 20, 4]],
    [82, [21, 12, 3], [4, 4, 20]],
    [86, [4, 20, 4], [4, 4, 20]],
    [88, [21, 12, 3], [4, 20, 20]],
    [89, [4, 4, 4], [4, 20, 20]],
    [90, [3, 12, 21], [21, 12, 3]],
    [96, [20, 4, 20], [20, 20, 4]],
    [97, [4, 4, 4], [20, 4, 20], [20, 20, 4]],
    [98, [12, 3, 21], [20, 20, 4]],
    [99, [4, 4, 4], [20, 20, 4]],
    [100, [12, 21, 3], [20, 4, 20]],
    [101, [4, 4, 4], [20, 4, 20]],
    [102, [12, 3, 21], [12, 21, 3]],
    [104, [4, 20, 20], [20, 4, 20], [20, 20, 4]],
    [105, [4, 4, 4], [4, 20, 20], [20, 4, 20], [20, 20, 4]],
    [106, [4, 20, 20], [20, 20, 4]],
    [107, [4, 4, 4], [20, 20, 4]],
    [108, [4, 20, 20], [20, 4, 20]],
    [109, [4, 4, 4], [20, 4, 20]],
    [120, [20, 4, 20], [4, 20, 20]],
    [121, [4, 4, 4], [4, 20, 20]],
    [126, [4, 4, 4], [20, 20, 20]],
    [129, [4, 4, 4], [20, 20, 20]],
    [130, [4, 4, 20], [20, 20, 20]],
    [131, [3, 3, 12], [20, 20, 20]],
    [132, [4, 20, 4], [20, 20, 20]],
    [133, [3, 12, 3], [20, 20, 20]],
    [134, [4, 4, 20], [4, 20, 4], [20, 20, 20]],
    [135, [4, 4, 20], [20, 20, 20]],
    [137, [12, 21, 21], [4, 4, 4]],
    [144, [20, 4, 4], [20, 20, 20]],
    [145, [12, 3, 3], [20, 20, 20]],
    [146, [4, 4, 20], [20, 4, 4], [20, 20, 20]],
    [147, [4, 4, 20], [20, 20, 20]],
    [148, [4, 20, 4], [20, 4, 4], [20, 20, 20]],
    [149, [4, 20, 4], [20, 20, 20]],
    [150, [4, 4, 20], [4, 20, 4], [20, 4, 4], [20, 20, 20]],
    [151, [4, 4, 20], [20, 20, 20]],
    [152, [12, 21, 21], [20, 4, 4]],
    [153, [12, 3, 3], [12, 21, 21]],
    [154, [4, 4, 20], [20, 4, 4]],
    [156, [4, 20, 4], [20, 4, 4]],
    [158, [4, 4, 20], [20, 4, 4]],
    [161, [21, 12, 21], [4, 4, 4]],
    [164, [21, 12, 21], [4, 20, 4]],
    [165, [3, 12, 3], [21, 12, 21]],
    [166, [4, 4, 20], [4, 20, 4]],
    [169, [4, 20, 20], [4, 4, 4]],
    [180, [20, 4, 4], [4, 20, 4]],
    [182, [4, 4, 20], [4, 20, 4]],
    [189, [20, 20, 4], [4, 4, 20]],
    [193, [21, 21, 12], [4, 4, 4]],
    [194, [21, 21, 12], [4, 4, 20]],
    [195, [3, 3, 12], [21, 21, 12]],
    [198, [4, 20, 4], [4, 4, 20]],
    [201, [4, 20, 20], [4, 4, 4]],
    [210, [20, 4, 4], [4, 4, 20]],
    [214, [4, 20, 4], [4, 4, 20]],
    [219, [20, 4, 20], [4, 20, 4]],
    [225, [20, 4, 20], [4, 4, 4]],
    [231, [4, 20, 20], [20, 4, 4]],
    [233, [4, 20, 20], [4, 4, 4]]
];

ambtab = [
    [61, 0, 0, 1],
    [62, 0, 0, -1],
    [91, 0, 1, 0],
    [94, 0, -1, 0],
    [103, 1, 0, 0],
    [110, 1, 0, 0],
    [111, 1, 0, 0],
    [118, -1, 0, 0],
    [122, 0, 1, 0],
    [123, 0, 1, 0],
    [124, 0, 0, 1],
    [125, 0, 0, 1],
    [155, 1, 0, 0],
    [157, 1, 0, 0],
    [159, 1, 0, 0],
    [167, 0, 1, 0],
    [173, 0, -1, 0],
    [181, 0, 1, 0],
    [183, 0, 1, 0],
    [185, -1, 0, 0],
    [188, 0, 0, -1],
    [190, 0, 0, -1],
    [199, 0, 0, 1],
    [203, 0, 0, -1],
    [211, 0, 0, 1],
    [215, 0, 0, 1],
    [217, -1, 0, 0],
    [218, 0, -1, 0],
    [222, 0, -1, 0],
    [227, 0, 0, -1],
    [229, 0, -1, 0],
    [230, -1, 0, 0],
    [235, 0, 0, -1],
    [237, 0, -1, 0],
    [246, -1, 0, 0],
    [249, -1, 0, 0]
];

axd_tab = [[1, 2], [1, 2], [0, 2], [0, 2], [0, 1], [0, 1]];
ax0_tab = [[0, 1, 0], [0, 1, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0], [1, 0, 0]];
ax1_tab = [[0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 0, 1], [0, 1, 0], [0, 1, 0]];
cas_tab = [0, 2, 0, 2, 0, 2];

import torch as th

class occupancy_dual_contouring:
    def __init__(self, device):
        self.device = device;
        self.vitogi = th.tensor(vitogi, dtype = th.int64, device = device);

        for a in lctab_2d: a += [[-1, -1, -1]] * (4 - len(a));
        self.lctab_2d = th.tensor(lctab_2d, dtype = th.int64, device = device);

        for a in pfvtab:
            for b in a: b += [0] * (15 - len(b));
            a += [[0] * 15] * (4 - len(a));
        self.pfvtab = th.tensor(pfvtab, dtype = th.int64, device = device);

        self.qvntab = th.div(th.sum(self.pfvtab > 0, dim = 2), 2, rounding_mode = 'floor');

        self.vtstab = th.sort(self.pfvtab.reshape(256, -1), dim = 1)[0][:, -32:];
        for i in range(4): self.vtstab[self.qvntab[:, i] > 0, i] = 25 + i;

        self.vbitab = th.zeros((256, 12), dtype = th.int64, device = device);
        for i in range(12):
            tmp = th.sum(self.pfvtab == i + 1, dim = 2);
            for j in range(4): self.vbitab[tmp[:, j] > 0, i] = j + 9;

        self.cstrtab = [[] for i in range(256)];
        for a in cstrtab: self.cstrtab[a[0]] = a[1:];
        for a in self.cstrtab: a += [[[0, 2, 1]]] * (4 - len(a));
        for a in self.cstrtab:
            for b in a: b += [[0, 2, 1]] * (2 - len(b));
        tmp = th.tensor(self.cstrtab, dtype = th.int64, device = device);
        self.cstrtab = th.stack((th.div(tmp, 4, rounding_mode = 'floor'),
                                 th.div(tmp, 2, rounding_mode = 'floor') % 2,
                                 tmp % 2), dim = 4).to(th.float64);

        self.cpnttab = [[] for i in range(256)];
        for a in cpnttab: self.cpnttab[a[0]] = a[1:];
        for a in self.cpnttab: a += [[12, 12, 12]] * (4 - len(a));
        self.cpnttab = th.tensor(self.cpnttab, dtype = th.float64, device = device) / 24.0;

        self.ambtab = [[0, 0, 0, 0] for _ in range(256)];
        for a in ambtab: self.ambtab[a[0]] = [1, a[1], a[2], a[3]];
        self.ambtab = th.tensor(self.ambtab, dtype = th.int64, device = device);

        self.axd_tab = th.tensor(axd_tab, dtype = th.int64, device = device);
        self.ax0_tab = th.tensor(ax0_tab, dtype = th.int64, device = device);
        self.ax1_tab = th.tensor(ax1_tab, dtype = th.int64, device = device);
        self.cas_tab = th.tensor(cas_tab, dtype = th.int64, device = device);

    @th.no_grad()
    def extract_mesh(
            self,
            imp_func,
            min_coord: list[float] = [-0.5, -0.5, -0.5],
            max_coord: list[float] = [ 0.5,  0.5,  0.5],
            num_grid: int = 128,
            isolevel: float = 0.0,
            batch_size: int = 100000000,
            imp_func_cplx: int = 3,
            outside: bool = True,
            BINARY_SEARCH: int = 15,
            VERTICAL_RANGE: float = 0.8,
            VERTICAL_LINEAR_SEARCH: int = 4,
            VERTICAL_BINARY_SEARCH: int = 11,
            HORIZNTL_RANGE: float = 0.71,
            HORIZNTL_LINEAR_SEARCH: int = 3,
            HORIZNTL_BINARY_SEARCH: int = 12,
            ERR: float = 3e-7,
            SEP: float = 1e-3,
            QEF_REG: float = 0.05
    ):
        GRID = num_grid;
        GRID_ = GRID + 1;
        GRID2_, GRID3_ = GRID_ ** 2, GRID_ ** 3;
        device = self.device;

        min_coordc = th.tensor(min_coord, dtype = th.float64, device = device).reshape(1, 3);
        siz_coordc = th.tensor(max_coord, dtype = th.float64, device = device).reshape(1, 3) - min_coordc;

        B = max(1, batch_size // imp_func_cplx);
        if outside: get_occv_ = lambda x: imp_func(x) < isolevel;
        else: get_occv_ = lambda x: imp_func(x) > isolevel;
        
        pidx1_to_pidx3 = lambda pi1: th.remainder(th.stack((th.div(pi1, GRID2_, rounding_mode = 'floor'),
                                                            th.div(pi1, GRID_, rounding_mode = 'floor'), pi1), dim = -1), GRID_);
        pidx3_to_pnts = lambda pi3: (pi3 / GRID).to(th.float64);

        def get_occv(cor_):
            if cor_.shape[0] == 0:
                return th.zeros((0,), dtype = th.bool, device = device);

            cor = min_coordc + cor_ * siz_coordc;
            if cor.shape[0] <= B: return get_occv_(cor);

            out = [];
            for cal_i in range(0, cor.shape[0], B):
                out.append(get_occv_(cor[cal_i: cal_i + B]));
            return th.cat(out, dim = 0);

        pidx1 = th.arange(GRID3_, dtype = th.int64, device = device);
        occs = get_occv(pidx3_to_pnts(pidx1_to_pidx3(pidx1))).reshape(GRID_, GRID_, GRID_);

        vals = th.zeros((GRID, GRID, GRID), dtype = th.uint8, device = device);
        vals += occs[ 1:,  1:,  1:]; vals <<= 1;
        vals += occs[ 1:,  1:, :-1]; vals <<= 1;
        vals += occs[ 1:, :-1,  1:]; vals <<= 1;
        vals += occs[ 1:, :-1, :-1]; vals <<= 1;
        vals += occs[:-1,  1:,  1:]; vals <<= 1;
        vals += occs[:-1,  1:, :-1]; vals <<= 1;
        vals += occs[:-1, :-1,  1:]; vals <<= 1;
        vals += occs[:-1, :-1, :-1];

        cel_pidx3 = th.argwhere((vals > 0) & (vals < 255));
        
        val_ = vals[cel_pidx3[:, 0], cel_pidx3[:, 1], cel_pidx3[:, 2]].to(th.int64);
        ambres = self.ambtab[val_];
        amb_idcs = th.argwhere(ambres[:, 0] == 1).reshape(-1);
        amb_pidx3 = cel_pidx3[amb_idcs] + ambres[amb_idcs, 1:];
        tpi = th.argwhere(th.sum((0 <= amb_pidx3) & (amb_pidx3 < GRID), dim = 1) == 3).reshape(-1);
        tmp = vals[amb_pidx3[tpi, 0], amb_pidx3[tpi, 1], amb_pidx3[tpi, 2]].to(th.int64);
        amb_pidx3 = amb_pidx3[tpi[self.ambtab[tmp, 0] == 1]];
        tmp = vals[amb_pidx3[:, 0], amb_pidx3[:, 1], amb_pidx3[:, 2]];
        vals[amb_pidx3[:, 0], amb_pidx3[:, 1], amb_pidx3[:, 2]] = 255 - tmp;
        amb_chks = th.zeros((GRID_, GRID_, GRID_), dtype = th.bool, device = device);
        amb_chks[amb_pidx3[:, 0], amb_pidx3[:, 1], amb_pidx3[:, 2]] = True;

        val_ = vals[cel_pidx3[:, 0], cel_pidx3[:, 1], cel_pidx3[:, 2]].to(th.int64);

        if cel_pidx3.shape[0] == 0:
            print("Occupancy Dual Contouring: No Surface Detected.");
            return th.zeros((0, 3), dtype = th.float64, device = device), \
                   th.zeros((0, 3), dtype = th.int64, device = device);

        vtcs = self.vtstab[val_];
        sel_pidx1 = self.vitogi[vtcs, 3] * GRID3_ + \
                    (cel_pidx3[:, 0:1] + self.vitogi[vtcs, 0]) * GRID2_ + \
                    (cel_pidx3[:, 1:2] + self.vitogi[vtcs, 1]) * GRID_ + \
                    (cel_pidx3[:, 2:3] + self.vitogi[vtcs, 2]);
        sel_pidx1 = sel_pidx1.reshape(-1);
        sel_pidx1 = th.unique(sel_pidx1[sel_pidx1 >= 0]);

        val_pnts = th.zeros((sel_pidx1.shape[0], 3), dtype = th.float64, device = device);

        def get_idx(q):
            S = q.shape; q_ = q.reshape(-1);
            std, idx = th.unique(th.cat((q_, sel_pidx1), dim = 0), return_inverse = True);
            return idx[:q_.shape[0]].reshape(S);

        def _1d_search(pidx3, axis, val_):
            P = pidx3.shape[0];
            pnts = pidx3_to_pnts(pidx3);
            left = th.zeros((P, 1), dtype = th.float64, device = device);
            rght =  th.ones((P, 1), dtype = th.float64, device = device);

            for _ in range(BINARY_SEARCH):
                mid = (left + rght) * 0.5;
                occv = get_occv(pnts + axis * (mid / GRID));

                jdge = (occv == val_).unsqueeze(1);
                left = th.where(jdge, mid, left);
                rght = th.where(jdge, rght, mid);

            return left * axis;

        start_idx = 0;
        pidx1 = sel_pidx1[(0 * GRID3_ <= sel_pidx1) & (sel_pidx1 < 3 * GRID3_)];
        count_idx = pidx1.shape[0];
        
        axis = th.zeros((count_idx, 3), dtype = th.float64, device = device);
        axis[(0 * GRID3_ <= pidx1) & (pidx1 < 1 * GRID3_), 2] = 1.0;
        axis[(1 * GRID3_ <= pidx1) & (pidx1 < 2 * GRID3_), 1] = 1.0;
        axis[(2 * GRID3_ <= pidx1) & (pidx1 < 3 * GRID3_), 0] = 1.0;

        pidx3 = pidx1_to_pidx3(pidx1);
        val_ = occs[pidx3[:, 0], pidx3[:, 1], pidx3[:, 2]];

        val_pnts[start_idx: start_idx + count_idx] = _1d_search(pidx3, axis, val_);
        start_idx += count_idx;
        

        def _2d_linbin(pnts, spnt, locc, axis, srch_range, lin_step, bin_step):
            P = pnts.shape[0];
            tstep = srch_range / lin_step;
            lidx = th.full((P,), lin_step, dtype = th.int64, device = device);
            locc = locc.reshape(-1);

            for lin_i in range(lin_step):
                cor_ = pnts + (spnt + axis * ((lin_step - lin_i) * tstep)) / GRID;
                occv = get_occv(cor_);
                lidx = th.where(occv != locc, lin_step - lin_i - 1, lidx);

            left = spnt + axis * (lidx.unsqueeze(1) * tstep);
            rght = left + axis * tstep;
            locc = locc.unsqueeze(1);

            for bin_i in range(bin_step):
                mid = (left + rght) * 0.5;
                occv = get_occv(pnts + mid / GRID).unsqueeze(1);

                jdge = locc == occv;
                left = th.where(jdge, mid, left);
                rght = th.where(jdge, rght, mid);
            
            return left;

        def _2d_search(pidx3, axdir, axis0, axis1, val_, cases):
            P = pidx3.shape[0];
            arng = th.arange(P, dtype = th.int64, device = device);
            pnts = pidx3_to_pnts(pidx3);
            axis0, axis1 = axis0.to(th.float64), axis1.to(th.float64);

            cidx3 = pidx3.clone();
            lcres = self.lctab_2d[val_, cases];
            cidx3[arng, axdir[:, 0]] += lcres[:, 0];
            cidx3[arng, axdir[:, 1]] += lcres[:, 1];
            edir = axdir[arng, lcres[:, 2]];
            cidx1 = (2 - edir) * GRID3_ + cidx3[:, 0] * GRID2_ + cidx3[:, 1] * GRID_ + cidx3[:, 2];
            linv = val_pnts[get_idx(cidx1)];
            lcord = th.where(lcres[:, 2:] == 0, linv, axis0 * lcres[:, 0: 1]) + \
                    th.where(lcres[:, 2:] == 1, linv, axis1 * lcres[:, 1: 2]);
            
            chk0 = cidx3.clone();
            occ0 = occs[chk0[:, 0], chk0[:, 1], chk0[:, 2]].unsqueeze(1);
            chk0 = (chk0 - pidx3).to(th.float64);

            chk1 = cidx3.clone(); chk1[arng, edir] += 1;
            occ1 = occs[chk1[:, 0], chk1[:, 1], chk1[:, 2]].unsqueeze(1);
            chk1 = (chk1 - pidx3).to(th.float64);
            
            cidx3 = pidx3.clone();
            lcres = self.lctab_2d[val_, cases + 1];
            cidx3[arng, axdir[:, 0]] += lcres[:, 0];
            cidx3[arng, axdir[:, 1]] += lcres[:, 1];
            edir = axdir[arng, lcres[:, 2]];
            cidx1 = (2 - edir) * GRID3_ + cidx3[:, 0] * GRID2_ + cidx3[:, 1] * GRID_ + cidx3[:, 2];
            linv = val_pnts[get_idx(cidx1)];
            rcord = th.where(lcres[:, 2:] == 0, linv, axis0 * lcres[:, 0: 1]) + \
                    th.where(lcres[:, 2:] == 1, linv, axis1 * lcres[:, 1: 2]);
            
            chk2 = cidx3.clone();
            occ2 = occs[chk2[:, 0], chk2[:, 1], chk2[:, 2]].unsqueeze(1);
            chk2 = (chk2 - pidx3).to(th.float64);

            chk3 = cidx3.clone(); chk3[arng, edir] += 1;
            occ3 = occs[chk3[:, 0], chk3[:, 1], chk3[:, 2]].unsqueeze(1);
            chk3 = (chk3 - pidx3).to(th.float64);

            spnt = (lcord + rcord) * 0.5;
            locc = get_occv(pnts + spnt / GRID).unsqueeze(1);

            hnorm = lcord - rcord;
            leng = th.norm(hnorm, dim = 1, keepdim = True);
            cndt = leng < ERR;
            leng[cndt] = 1.0;
            hnorm = hnorm / leng;
            vnorm = th.cross(th.cross(axis0, axis1, dim = 1), hnorm, dim = 1);
            
            tmp = th.sum((chk0 - spnt) * vnorm, dim = 1, keepdim = True);
            vnorm = th.where((th.abs(tmp) > ERR) & th.bitwise_xor(tmp > 0, locc != occ0), -vnorm, vnorm);

            tmp = th.sum((chk1 - spnt) * vnorm, dim = 1, keepdim = True);
            vnorm = th.where((th.abs(tmp) > ERR) & th.bitwise_xor(tmp > 0, locc != occ1), -vnorm, vnorm);

            tmp = th.sum((chk2 - spnt) * vnorm, dim = 1, keepdim = True);
            vnorm = th.where((th.abs(tmp) > ERR) & th.bitwise_xor(tmp > 0, locc != occ2), -vnorm, vnorm);

            tmp = th.sum((chk3 - spnt) * vnorm, dim = 1, keepdim = True);
            vnorm = th.where((th.abs(tmp) > ERR) & th.bitwise_xor(tmp > 0, locc != occ3), -vnorm, vnorm);

            left = _2d_linbin(pnts, spnt, locc, vnorm,
                              VERTICAL_RANGE, VERTICAL_LINEAR_SEARCH, VERTICAL_BINARY_SEARCH);
            vl = th.sum((left - spnt) * vnorm, dim = 1, keepdim = True);
            cndt |= th.abs(vl) < ERR;

            lleft = _2d_linbin(pnts, left, locc, hnorm,
                               HORIZNTL_RANGE, HORIZNTL_LINEAR_SEARCH, HORIZNTL_BINARY_SEARCH) - lcord;
            lh = th.sum(lleft * hnorm, dim = 1, keepdim = True);
            rleft = _2d_linbin(pnts, left, locc, -hnorm,
                               HORIZNTL_RANGE, HORIZNTL_LINEAR_SEARCH, HORIZNTL_BINARY_SEARCH) - rcord;
            rh = th.sum(rleft * hnorm, dim = 1, keepdim = True);

            denm = rh - lh;
            cndt |= th.abs(denm) < ERR;
            rslt = ((0.5 * (rh + lh)) * hnorm + vl * vnorm) * (leng / denm);
            
            cndt |= th.sum(rslt * vnorm, dim = 1, keepdim = True) < 0;
            rslt = th.where(cndt, th.zeros_like(rslt), rslt);
            return spnt + rslt;
        
        
        pidx1 = sel_pidx1[(3 * GRID3_ <= sel_pidx1) & (sel_pidx1 < 9 * GRID3_)];
        count_idx = pidx1.shape[0];

        csidx = th.div(pidx1, GRID3_, rounding_mode = 'floor') - 3;
        axdir = self.axd_tab[csidx];
        axis0 = self.ax0_tab[csidx];
        axis1 = self.ax1_tab[csidx];
        cases = self.cas_tab[csidx];
        axis2 = axis0 + axis1;

        pidx3 = pidx1_to_pidx3(pidx1);
        val_ =     occs[pidx3[:, 0]              , pidx3[:, 1]              , pidx3[:, 2]              ] + \
               2 * occs[pidx3[:, 0] + axis1[:, 0], pidx3[:, 1] + axis1[:, 1], pidx3[:, 2] + axis1[:, 2]] + \
               4 * occs[pidx3[:, 0] + axis0[:, 0], pidx3[:, 1] + axis0[:, 1], pidx3[:, 2] + axis0[:, 2]] + \
               8 * occs[pidx3[:, 0] + axis2[:, 0], pidx3[:, 1] + axis2[:, 1], pidx3[:, 2] + axis2[:, 2]];
        tmp = amb_chks[pidx3[:, 0], pidx3[:, 1], pidx3[:, 2]];
        val_[tmp] = 15 - val_[tmp];
        
        val_pnts[start_idx: start_idx + count_idx] = _2d_search(pidx3, axdir, axis0, axis1, val_, cases);
        start_idx += count_idx;


        def _solve_QEF(pidx3, val_, cases):
            out = th.zeros((pidx3.shape[0], 3), dtype = th.float64, device = device);

            for i in range(3, 8):
                idx = th.argwhere(self.qvntab[val_, cases] == i).reshape(-1);
                pid3_ = pidx3[idx]; val0_ = val_[idx]; cas = cases[idx];
                vtcs = self.pfvtab[val0_, cas, :2 * i + 1];
                vitg = self.vitogi[vtcs];

                pnti = vitg[:, :, 3] * GRID3_ + \
                       (pid3_[:, 0:1] + vitg[:, :, 0]) * GRID2_ + \
                       (pid3_[:, 1:2] + vitg[:, :, 1]) * GRID_ + \
                       (pid3_[:, 2:3] + vitg[:, :, 2]);

                pidx = get_idx(pnti);
                vert = val_pnts[pidx];
                vert += vitg[:, :, :3];

                _1vt = vert[:, 1::2];
                qnrm = th.cross(_1vt - vert[:, :-1:2], _1vt - vert[:, 2::2], dim = 2);
                cntr = th.mean(_1vt, dim = 1);

                anrm = th.norm(qnrm, dim = 2, keepdim = True);
                cndt = anrm < ERR;
                qnrm /= th.where(cndt, th.ones_like(anrm), anrm);
                cndt = th.sum(cndt, dim = 1) == cndt.shape[1];

                eye_ = th.eye(3, dtype = th.float64, device = device).view(1, 3, 3).repeat(cntr.shape[0], 1, 1);
                qefr = th.linalg.lstsq(th.cat((qnrm, QEF_REG * eye_), dim = 1),
                                    th.cat((th.sum(_1vt * qnrm, dim = 2, keepdim = True),
                                            QEF_REG * cntr.unsqueeze(2)), dim = 1)).solution.reshape(-1, 3);
                qefr = th.where(cndt, cntr, qefr);

                cpnt = self.cpnttab[val0_, cas];
                ctoq = qefr - cpnt;
                leng = th.norm(ctoq, dim = 1, keepdim = True);

                cscd = self.cstrtab[val0_, cas];
                cvtx = cscd[:, :, 0];
                cnml = th.cross(cscd[:, :, 2] - cvtx, cscd[:, :, 1] - cvtx, dim = 2);
                t = th.sum(cnml * (cvtx - cpnt.unsqueeze(1)), dim = 2) / th.sum(cnml * ctoq.unsqueeze(1), dim = 2);

                t = th.cat(((1.0 - cpnt) / ctoq, -cpnt / ctoq, t), dim = 1) * leng;
                cndt = (t < 0) | th.isnan(t);
                t[cndt] = leng.repeat(1, 8)[cndt] + SEP;
                t = (t - SEP) / th.where(leng < ERR, th.ones_like(leng), leng);
                t = th.min(th.clamp(t, 0.0, 1.0), dim = 1, keepdim = True)[0];

                out[idx] = cpnt + t * ctoq;
            
            return out;

        pidx1 = sel_pidx1[9 * GRID3_ <= sel_pidx1];
        count_idx = pidx1.shape[0];
        pidx3 = pidx1_to_pidx3(pidx1);
        val_ = vals[pidx3[:, 0], pidx3[:, 1], pidx3[:, 2]].to(th.int64);
        cases = th.div(pidx1, GRID3_, rounding_mode = 'floor') - 9;
        
        val_pnts[start_idx: start_idx + count_idx] = _solve_QEF(pidx3, val_, cases);
        start_idx += count_idx;

        def _get_face():
            faces = [];

            cndts, vidcs, vpnts = [], [], [];
            evofs = [];
            idcs = th.tensor([[[12], [8], [6], [1]],
                              [[11], [4], [9], [2]],
                              [[10], [7], [5], [3]]], dtype = th.int64, device = device);
            ofst = th.tensor([[[0], [GRID_ ], [GRID2_], [GRID2_ + GRID_]],
                              [[0], [GRID2_], [1     ], [GRID2_ + 1    ]],
                              [[0], [1     ], [GRID_ ], [1      + GRID_]]],
                             dtype = th.int64, device = device);
            vofs = th.tensor([[[0, 0, 0], [0, 1, 0], [1, 0, 0], [1, 1, 0], [1, 1, 0]],
                              [[0, 0, 0], [1, 0, 0], [0, 0, 1], [1, 0, 1], [1, 0, 1]],
                              [[0, 0, 0], [0, 0, 1], [0, 1, 0], [0, 1, 1], [0, 1, 1]]],
                             dtype = th.int64, device = device).unsqueeze(2);

            z, y, x = th.argwhere(th.bitwise_xor(occs[1:-1, 1:-1, :-1], occs[1:-1, 1:-1, 1:])).T;
            val_ = vals[z.unsqueeze(0) + vofs[0, :4, 0, 0:1],
                        y.unsqueeze(0) + vofs[0, :4, 0, 1:2],
                        x.unsqueeze(0) + vofs[0, :4, 0, 2:3]].to(th.int64);
            fac_idx = (z * GRID2_ + y * GRID_ + x).unsqueeze(0);
            vidx3 = self.vbitab[val_, idcs[0] - 1] * GRID3_ + fac_idx + ofst[0];
            gvidx = get_idx(th.cat((vidx3, fac_idx + (GRID2_ + GRID_)), dim = 0));
            gvpnt = val_pnts[gvidx] + vofs[0].to(th.float64);

            cndts.append(occs[z + 1, y + 1, x + 1]);
            vidcs.append(gvidx.clone());
            vpnts.append(gvpnt.clone());
            evofs.append(vofs[0, 4].repeat(x.shape[0], 1));

            z, y, x = th.argwhere(th.bitwise_xor(occs[1:-1, :-1, 1:-1], occs[1:-1, 1:, 1:-1])).T;
            val_ = vals[z.unsqueeze(0) + vofs[1, :4, 0, 0:1],
                        y.unsqueeze(0) + vofs[1, :4, 0, 1:2],
                        x.unsqueeze(0) + vofs[1, :4, 0, 2:3]].to(th.int64);
            fac_idx = (z * GRID2_ + y * GRID_ + x).unsqueeze(0);
            vidx3 = self.vbitab[val_, idcs[1] - 1] * GRID3_ + fac_idx + ofst[1];
            gvidx = get_idx(th.cat((vidx3, fac_idx + (GRID3_ + GRID2_ + 1)), dim = 0));
            gvpnt = val_pnts[gvidx] + vofs[1].to(th.float64);

            cndts.append(occs[z + 1, y + 1, x + 1]);
            vidcs.append(gvidx.clone());
            vpnts.append(gvpnt.clone());
            evofs.append(vofs[1, 4].repeat(x.shape[0], 1));

            z, y, x = th.argwhere(th.bitwise_xor(occs[:-1, 1:-1, 1:-1], occs[1:, 1:-1, 1:-1])).T;
            val_ = vals[z.unsqueeze(0) + vofs[2, :4, 0, 0:1],
                        y.unsqueeze(0) + vofs[2, :4, 0, 1:2],
                        x.unsqueeze(0) + vofs[2, :4, 0, 2:3]].to(th.int64);
            fac_idx = (z * GRID2_ + y * GRID_ + x).unsqueeze(0);
            vidx3 = self.vbitab[val_, idcs[2] - 1] * GRID3_ + fac_idx + ofst[2];
            gvidx = get_idx(th.cat((vidx3, fac_idx + (2 * GRID3_ + 1 + GRID_)), dim = 0));
            gvpnt = val_pnts[gvidx] + vofs[2].to(th.float64);

            cndts.append(occs[z + 1, y + 1, x + 1]);
            vidcs.append(gvidx.clone());
            vpnts.append(gvpnt.clone());
            evofs.append(vofs[2, 4].repeat(x.shape[0], 1));


            cndts, vidcs, vpnts = th.cat(cndts, dim = 0), th.cat(vidcs, dim = 1), th.cat(vpnts, dim = 1);
            evofs = th.cat(evofs, dim = 0).to(th.float64).unsqueeze(0);

            idcs = th.tensor([0, 1, 3, 2, 0, 1], dtype = th.int64, device = device);
            pnts1 = vpnts[idcs[0: 4]]; pnts2 = vpnts[idcs[1: 5]]; pnts3 = vpnts[idcs[2: 6]];
            sitst = th.sum(th.cross(pnts1 - evofs, pnts3 - evofs, dim = 2) * (pnts2 - evofs), dim = 2) < 0;
            sitst |= th.sum(th.cross(pnts1 - 1.0, pnts3 - 1.0, dim = 2) * (pnts2 - 1.0), dim = 2) > 0;

            sit12 = sitst[0] | sitst[2];
            sit03 = sitst[1] | sitst[3];
            sitsp = sit12 & sit03;
            sitnp = ~sitsp;

            idcs0, idcs1, idcs2, idcs3, eidcs = vidcs[:, sitsp];
            faces = th.cat((th.stack((idcs1, idcs0, eidcs), dim = 1),
                            th.stack((idcs3, idcs1, eidcs), dim = 1),
                            th.stack((idcs2, idcs3, eidcs), dim = 1),
                            th.stack((idcs0, idcs2, eidcs), dim = 1)), dim = 0);

            idcs0, idcs1, idcs2, idcs3, _ = vidcs[:, sitnp];
            pnts0, pnts1, pnts2, pnts3, epnts = vpnts[:, sitnp];
            sit12, sit03 = sit12[sitnp], sit03[sitnp];

            v03 = pnts3 - pnts0;
            leng = th.norm(v03, dim = 1);
            cnn03 = leng < ERR;
            v03 /= th.where(cnn03, th.ones_like(leng), leng).unsqueeze(1);

            ev0s = epnts - pnts0;
            t_ = th.sum(ev0s * v03, dim = 1);
            vp03 = pnts0 + t_.unsqueeze(1) * v03;

            n1 = th.cross(v03, pnts1 - pnts0, dim = 1);
            ln1 = th.norm(n1, dim = 1);
            bnn03 = ln1 < ERR;
            t_ = th.sum(ev0s * n1, dim = 1) / th.clamp(ln1, 1e-5) ** 2;
            vp1 = epnts - t_.unsqueeze(1) * n1;
            cndt = th.sum(th.cross(v03, vp1 - pnts0, dim = 1) * n1, dim = 1) > 0;
            vp1 = th.where(cndt.unsqueeze(1), vp1, vp03);

            n2 = th.cross(v03, pnts2 - pnts0, dim = 1);
            ln2 = th.norm(n2, dim = 1);
            bnn03 |= ln2 < ERR;
            t_ = th.sum(ev0s * n2, dim = 1) / th.clamp(ln2, 1e-5) ** 2;
            vp2 = epnts - t_.unsqueeze(1) * n2;
            cndt = th.sum(th.cross(v03, vp2 - pnts0, dim = 1) * n2, dim = 1) > 0;
            vp2 = th.where(cndt.unsqueeze(1), vp2, vp03);

            lf03 = th.minimum(th.norm(vp1 - epnts, dim = 1), th.norm(vp2 - epnts, dim = 1));

            v12 = pnts2 - pnts1;
            leng = th.norm(v12, dim = 1);
            cnn12 = leng < ERR;
            v12 /= th.where(cnn12, th.ones_like(leng), leng).unsqueeze(1);

            ev1s = epnts - pnts1;
            t_ = th.sum(ev1s * v12, dim = 1);
            vp12 = pnts1 + t_.unsqueeze(1) * v12;

            n0 = th.cross(v12, pnts0 - pnts1, dim = 1);
            ln0 = th.norm(n0, dim = 1);
            t_ = th.sum(ev1s * n0, dim = 1) / th.clamp(ln0, 1e-5) ** 2;
            vp0 = epnts - t_.unsqueeze(1) * n0;
            cndt = th.sum(th.cross(v12, vp0 - pnts1, dim = 1) * n0, dim = 1) > 0;
            vp0 = th.where(cndt.unsqueeze(1), vp0, vp12);

            n3 = th.cross(v12, pnts3 - pnts1, dim = 1);
            ln3 = th.norm(n3, dim = 1);
            t_ = th.sum(ev1s * n3, dim = 1) / th.clamp(ln3, 1e-5) ** 2;
            vp3 = epnts - t_.unsqueeze(1) * n3;
            cndt = th.sum(th.cross(v12, vp3 - pnts1, dim = 1) * n3, dim = 1) > 0;
            vp3 = th.where(cndt.unsqueeze(1), vp3, vp12);

            lf12 = th.minimum(th.norm(vp0 - epnts, dim = 1), th.norm(vp3 - epnts, dim = 1));

            cnn12 |= (lf12 < lf03) | bnn03 | sit12;
            cnn12 &= ~(cnn03 | sit03);

            faces = th.cat((th.where(cnn12.unsqueeze(1),
                                     th.stack((idcs0, idcs2, idcs1), dim = 1),
                                     th.stack((idcs0, idcs3, idcs1), dim = 1)),
                            th.where(cnn12.unsqueeze(1),
                                     th.stack((idcs1, idcs2, idcs3), dim = 1),
                                     th.stack((idcs0, idcs2, idcs3), dim = 1)),
                            faces), dim = 0);
            
            cndtn, cndts = cndts[sitnp], cndts[sitsp];
            cndts = th.cat((cndtn, cndtn, cndts, cndts, cndts, cndts));
            ftmp = faces[cndts, 1:3].clone();
            faces[cndts, 1] = ftmp[:, 1]; faces[cndts, 2] = ftmp[:, 0];

            return th.unique(faces, return_inverse = True);

        vidcs, faces = _get_face();

        pidx1 = sel_pidx1[vidcs];
        pnts = pidx3_to_pnts(pidx1_to_pidx3(pidx1)) + val_pnts[vidcs] / GRID;
        verts = min_coordc + pnts * siz_coordc;

        return verts, faces;

